package jpave.dataholders;
/**
* The main routine is createPAVElistFromJpaveConfig run at startup
* It creates a Session object for each Assembly 
* CAS - I'm not sure why the Session and Assembly are separate, except
* possibly because Brian used to have two assemblies in a session.
*/

import java.io.File;
import java.io.Serializable;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Vector;

import jpave.query_interface.BasicQueryTab;
import jpave.query_interface.JPaveMain;
import jpave.database.JPaveDBWrapper;
import util.Debug.ErrorReport;
import util.methods.Converters;
import util.methods.HostsCfg;
import util.methods.StringHelpers;
import util.methods.Version;

public class SessionData implements Serializable {
	private static final long serialVersionUID = -5545548627175908589L;
	// So classes can either use this or JPaveMain debug for jpave -v output
	// this will allow us to output what we want user's to send us in case of error
	public boolean debug;
	public SessionData() {debug = JPaveMain.debug;}

	public AssemblyData getAllAssembly() {return assembly;}
	public void addAssembly(AssemblyData inAssembly) {assembly = inAssembly;}
	
	public void setStartURL(String strURL) {startURL = strURL;}
	public String getStartURL() {return startURL;}
	public File getStatsHTMLDir() {return statsHTMLDir;}
	public void setStatsHTMLDir(File startHTMLDir) {this.statsHTMLDir = startHTMLDir;}
	
	public String toString() {return getFullDescription();}
	public void setDescription(String description) {this.description = description;}

	public String getID() {
		return assembly.getAssemblyID();
	}

	public String getDescription() {
		String strDescription;
	
		AssemblyData ad = getAssembly(0);
		strDescription = ad.getDescription();

		if (!StringHelpers.isEmpty(strDescription))
			return strDescription;
		else
			return getID();
	}

	/**
	 * Returns a string that is displayed on the PAVE assemblies window
	 */
	public String getFullDescription() {
		String assmID = getDescription();

		AssemblyData ad = getAssembly(0);
			
		if (ad.getDBData() == null) return assmID;
		
		/*doesn't work on graphical display, i.e. formating not right
		 * String str = String.format("%15s %20s db%4s %10s %s", 
				assmID, ad.getDBData().getDBName(), ad.getDBversion(),
				ad.getAssemblyDate(),  ad.getAssemblyUser()); */
		
		String str = assmID + "    [" + ad.getDBData().getDBName() + " "
						+ ad.getAssemblyDate() + " " + ad.getAssemblyUser()
						+ "]";
		String db = ad.getDBversion();
		if (!db.equals(Version.strDBver)) str += " db" + db;

		return str;
	}
	public String getViewDescription() {
		String assmID = getDescription();

		AssemblyData ad = getAssembly(0);
			
		if (ad.getDBData() == null) return assmID;
		
		String str = assmID + "    " +  ad.getDBData().getDBName();
		
		return str;
	}
	/*********** Major methods *****************/
	/**
	 * MAJOR METHOD to load databases and assemblies on startup
	 * Called from GlobalSettings.loadFromHosts
	 * 1. Calls DataBase.loadJPaveConfigFile to read jpave.config to return list of assemblies
	 *  // e.g. BAM 
		//		PAVE_test			Class DatabaseData
		//			assembly1		Class AssemblyData
		//			assembly2
		//		PAVE_bmk
		//			assembly1
		//		TAQ
		//			etc
	 * 2. Calls AssemblyData.getAssmInfoForEachAssm to get info on each assembly
	 * 		for display on PAVE Assemblies window
	 * 3. Calls 
	 */

	static public Vector<SessionData> createPAVElistForHost(String host)
			throws Exception {
		HostsCfg hosts = new HostsCfg();
		Vector<DatabaseData> dbList = DatabaseData.loadAllPAVEonHost(hosts.host,
				hosts.user, hosts.pass, hosts.user, hosts.pass, 0);
		Vector<AssemblyData> assemblyList = AssemblyData.getAssmInfoForEachAssm(dbList);

		Vector<SessionData> list = new Vector<SessionData>();
		for (AssemblyData ad : assemblyList) {
			// Setup the object for the current multiple assembly list
			SessionData newSession = new SessionData();
			newSession.setDescription("<session description>");
			newSession.setStartURL("");
			newSession.setStatsHTMLDir(null);

			newSession.addAssembly(ad);
			list.add(newSession);
		}
		return list;
	}
	/**
	 * Creates the text for the assembly Overview page
	 * Called from JpaveFrame.addOverviewTab
	 * calls assemblyData.overview which calls JPaveDBWrapper.overview
	 */
	public boolean overview(Vector<String> lines) throws Exception {
		String strFailedTask = "";
		try {
			AssemblyData assembly = getAssembly(0);
			if (!lines.isEmpty())
					lines.add(" ");

			if (!assembly.overview(lines))
				return false;

			// Test the start page URL
			if (!StringHelpers.isEmpty(startURL)) {
				strFailedTask = "Failed while testing start page URL.";
				startURL = StringHelpers.normalizeURL(startURL);
				new URL(startURL);
			}
			return true;
		} catch (Exception err) {
			lines.add(strFailedTask);
			lines.addAll(Converters.getMessageLines(err));
			return false;
		}
	}
    /********************************************
     * returns array of libName1, libTitle1, libName2, etc
     */
	public String[] getLibraries() throws Exception {
		String[] lib_names = null;

		Connection conn = getConnection();
		lib_names = JPaveDBWrapper.getLibs(conn, this.getID(), true);
		conn.close();

		return lib_names;
	}
	
	public String [] getAnnoDBs() throws Exception {
		String [] retVal = null;
		
		Connection conn = getConnection();
		retVal = JPaveDBWrapper.getAnnoTypes(conn, this.getID());
		conn.close();
		
		return retVal;
	}

	public String[] getContigSets() throws Exception {
		String[] lib_names = null;

		Connection conn = getConnection();
		lib_names = JPaveDBWrapper.getLibs(conn, this.getID(), false);
		conn.close();

		return lib_names;
	}
	
	public String[] getPColumns() throws Exception {
		String [] pCols = null;
		
		Connection conn = getConnection();
		pCols = JPaveDBWrapper.getPrefixedColumns(conn, "P_");
		conn.close();
		
		return pCols;
	}
	public String[] getPTitle(String [] pCol) throws Exception {
		String [] titles = null;
		
		Connection conn = getConnection();
		titles = JPaveDBWrapper.getPColTitles(conn, pCol);
		conn.close();
		
		return titles;
	}
	public boolean hasUpDownDE() throws Exception {

		Connection conn = getConnection();
		String[] pCols = JPaveDBWrapper.getPrefixedColumns(conn, "P_");
		boolean ret = false;
		if (pCols.length > 0)
		{
			Statement s = conn.createStatement();
			for (String col : pCols)
			{
				ResultSet rs = s.executeQuery("select contigid from contig where P_" + col + " < 0 limit 1");
				if (rs.first())
				{
					ret = true;
					break;
				}
			}
		}
		return ret;
	}
    // No longer multiple assemblies in a database, but still has residual code
	public String getAssemblyIDList(boolean bIncludeInter) {
		// Create an assembly predicate for doing queries

		String strList = "'" + assembly.getAssemblyID() + "'";

		// Add the inter-assembly id as indicated
		if (bIncludeInter)
			strList += ", '" + getID() + "'";

		return "( " + strList + " )";
	}

	public Connection getConnection() throws Exception {
		try {			
			return assembly.createConnection();
		} catch (Exception err) {
			return null;
		}
	}
	
	public AssemblyData getAssembly(int i) {return assembly;}

	// TODO is this crap?
	public void crossIndexCAP3Output(Vector<ContigData> contigList)
			throws Exception {

		JPaveDBWrapper db = assembly.createDBConnection();

			// Get as much data as we can for each contig using this database
		for (int i = 0; i < contigList.size(); ++i) {
			ContigData contig = (ContigData) contigList.get(i);
			db.crossIndexCAP3Output(contig);
		}
		db.close();
	}

	/**
	 * 
	 * Methods from ListQueryField for Basic Contig Query
	 */
	public ArrayList<Object []> loadContigIDs(String searchStr, BasicQueryTab qTab)
			throws Exception {
		JPaveDBWrapper curDB = assembly.createDBConnection();
		ArrayList<Object []> x = curDB.loadContigIDsInAssembly(searchStr, qTab);
		curDB.close();
		return x;
	}

	public ArrayList<Object []> loadContigWithHitID(String searchStr, BasicQueryTab qTab)
			throws Exception {

		JPaveDBWrapper curDB = assembly.createDBConnection();
		ArrayList<Object []> x = curDB.loadContigsByHitIDInAssembly(searchStr, qTab);	
		curDB.close();
		return x;
	}

	public ArrayList<Object []> loadContigWithHitDescription(	String searchStr, BasicQueryTab qTab)
			throws Exception {

		JPaveDBWrapper curDB = assembly.createDBConnection();
		ArrayList<Object []> x = curDB.loadContigsByHitDescriptionInAssembly(searchStr, qTab);	
		curDB.close();
		return x;
	}

	public ArrayList<Object []> loadContigWithNotes(String searchStr, BasicQueryTab qTab)
			throws Exception {

		JPaveDBWrapper curDB = assembly.createDBConnection();
		ArrayList<Object []> x = curDB.loadContigsByNotesInAssembly(searchStr, qTab);
		curDB.close();
		return x;
	}

	// Loads the ests for the input IDs for CAPorPhrap
	public Vector<SequenceData> loadClones(TreeSet<String> theIDs)
			throws Exception {
		TreeSet<String> missingESTs = new TreeSet<String>();
		missingESTs.addAll(theIDs);
		Vector<SequenceData> out = new Vector<SequenceData>();

		JPaveDBWrapper curDB = assembly.createDBConnection();
		Vector<SequenceData> curClones = curDB.loadClones(missingESTs
					.iterator());
		out.addAll(curClones);

		// See what clones are left to find
		for (int i = 0; i < curClones.size(); ++i) {
			SequenceData curSeq = (SequenceData) curClones.elementAt(i);
			missingESTs.remove(curSeq.getName());
		}
		curDB.close();
		return out;
	}
	// called by BasicQueryResultListPanel.addListFromQuery for Basic search
	public ArrayList<Object []> loadCloneIDs(String searchStr, boolean includeBuried, int limit) throws Exception {

			JPaveDBWrapper curDB = assembly.createDBConnection();
			ArrayList<Object[]> x = curDB.loadCloneIDsWithContig(searchStr, includeBuried, limit);
			curDB.close();
			return x;
	}
	
	// called from MainTopRowTab.loadESTsAndRun
	public void loadContigBuriedSequences(MainData theCluster, boolean loadLocation) throws Exception {
		try {
			JPaveDBWrapper curDB = assembly.createDBConnection();
			curDB.loadContigBuriedSequences(theCluster, loadLocation);
			curDB.close();
		} catch (SQLException e) { 
			String s = "Could not load contig buried sequences";
			System.err.println(s);
			ErrorReport.reportError(e, s);
		} 
	}

	// called from MainTopRowTab.loadESTsAndRun
	public MainData loadContigSequences(MainData inCluster) throws Exception {
		MainData outCluster = (MainData) Converters.deepCopy(inCluster);
		try {
			JPaveDBWrapper curDB = assembly.createDBConnection();
			curDB.loadContigUnburiedSequences(outCluster);
			curDB.close();
			return outCluster;
		} catch (SQLException e) { 
			String s = "Could not load contig sequences";
			System.err.println(s);
			ErrorReport.reportError(e, s);
            return null;
		} 
	}
	
	public String getCAPparams() throws Exception {
		JPaveDBWrapper curDB = assembly.createDBConnection();
		String x =  curDB.getCAPparams();
		curDB.close();
		return x;
	}

	public BlastHitData loadPairHitData(String ctg1, String ctg2) throws Exception {
		JPaveDBWrapper curDB = assembly.createDBConnection();
		BlastHitData x =  curDB.loadPairHitData(ctg1, ctg2);
		curDB.close();
		return x;
	}
	
	// Returns a Vector with all of the session assemblies
	public static Vector<SessionData> getAssemblySessions(
			Vector<SessionData> inSessions) {
		Vector<SessionData> out = new Vector<SessionData>();
		for (SessionData theSession : inSessions) {
			out.add(theSession);
		}
		return out;
	}

	/************* Instance variables *****************************/
	private AssemblyData assembly = null;
	String description = "Unnamed assembly";

	private String startURL = "";
	private File statsHTMLDir = null;
	private int nTotalContigs = 0;
}
